Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization

Friend Class TH_BikiRom_Up
    Inherits Threads.MultiVersionThread

    Private Enum upload_error
        eUpErrCRC
        eUpErrErase
        eUpErrFlashTimeout
        eUpErrFlashFault
        eUpErrCopy
        eUpErrUpload
        eUpErrUploadOK
    End Enum

    Friend Sub New(ByRef UsbHandler As Comm.UsbCommunicationHandle, ByRef car As CarBase, ByVal Action As BikiAction)
        MyBase.New("Uploading")
        m_UsbCommHandler = UsbHandler
        m_Action = Action
        m_carBase = car
    End Sub

    Private Sub OnErrMessage(ByVal upErr As upload_error, ByVal Map As UInt16, Optional ByVal Bank As Int16 = -1)
        Dim message As String = ""
        Dim strBank As String = ""
        Dim strMap As String

        If Bank <> -1 Then
            strBank = String.Format(" Bank {0}", Bank)
        End If

        strMap = String.Format(" Map {0}", Map)

        Select Case upErr
            Case upload_error.eUpErrCopy
                message = "Failed to copy to "
            Case upload_error.eUpErrCRC
                message = "Failed to upload CRC to "
            Case upload_error.eUpErrFlashTimeout
                message = "Flash Erase Timed out"
            Case upload_error.eUpErrFlashFault
                message = "Flash Erase Fault"
            Case upload_error.eUpErrErase
                message = "Failed to erase "
            Case upload_error.eUpErrUpload
                message = "Failed to upload data to "
            Case upload_error.eUpErrUploadOK
                message = "Successfuly uploaded "
            Case Else
                message = "Failed on "
        End Select

        message = message + strMap + strBank

        OnMessage(message)
    End Sub

    ''' <summary>
    ''' Performs a Upload given the action and the data for a Bikirom Version 2 Hardware Board
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Overrides Function HwV2Process() As thread_result
        Dim upData(2)() As Byte
        Dim upCarData() As Byte = Nothing
        Dim sectors()() As typFlashSector = Me.HwV2Sectors
        Dim data()() As Byte = m_carBase.Maps
        Dim uint_crc As UInteger
        Dim bStatus As Boolean = True
        Dim bReset As Boolean = False
        mProgressMax = 0

        ' Establish the maximum number of sectors that require erasing/uploading
        Dim sectorCount As Integer = 0
        For i As Integer = 0 To 2
            If m_Action And (2 ^ i) AndAlso Not IsNothing(data(i)) AndAlso data(i).Length = SectorSize Then
                ReDim upData(i)(SectorSize - 1)

                ' Copy the array
                Array.Copy(m_carBase.getMap(i), 0, upData(i), 0, SectorSize)
                ' Inject CRC and security

                InjectSecurityCrc(upData(i))

                CalculateCrc(upData(i), sectors(i))

                Select Case i
                    Case 0
                        Me.m_UsbCommHandler.GetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC, uint_crc)
                    Case 1
                        Me.m_UsbCommHandler.GetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_2, uint_crc)
                    Case 2
                        Me.m_UsbCommHandler.GetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_3, uint_crc)
                End Select

                Debug.Print(String.Format("Up S:{0} {1} vs {2}", i, sectors(i)(0).nCrc, uint_crc))

                ' Exclude self! no worries
                If sectors(i)(0).nCrc = uint_crc Then
                    m_Action = m_Action And (&HFFFFFFFFUL Xor CUInt(2 ^ i))
                Else
                    mProgressMax += SectorSize
                End If
            Else
                ' Exclude self if not correctly set up
                m_Action = m_Action And (&HFFFFFFFFUL Xor CUInt(2 ^ i))
            End If
        Next

        ' Prepare the car file for uploading!
        If m_Action And BikiAction.BK_CFG Then
            ' Serialize..
            upCarData = SerializeCarData(False)

            mProgressMax += upCarData.Length

            m_Action = m_Action Or BikiAction.BK_EEPROM
        End If

        ' Upload EEPROM data
        If m_Action And BikiAction.BK_EEPROM Then
            mProgressMax += CarBase.EEPROM_SIZE
            Try
                UploadEEPROM(m_carBase.getBikSettings.Data, 2)

                Me.m_UsbCommHandler.ResetDevice()
            Catch
                bStatus = False
            End Try
        End If

        If bStatus Then
            Dim timeout As Integer = 40

            While timeout > 0 And Not Me.m_UsbCommHandler.Initialised
                Threading.Thread.Sleep(100)
                timeout -= 1
            End While

            If Not Me.m_UsbCommHandler.Initialised Then
                bStatus = False
            End If
        End If

        If bStatus AndAlso m_Action And BikiAction.BK_MAPS AndAlso Me.m_UsbCommHandler.UsbInformation.OsVersion >= &H1D Then
            Debug.Print("Begining the Upload w/ Copy functions")

            Dim bReturn As thread_result = UploadFastVerified(sectors, upData, 0)

            If bReturn <> thread_result.rslt_allok Then
                Return bReturn
            Else
                Dim nCrcCheck As UInt32
                ' Set all the CRC-32's to OK if they successed
                For i As Integer = 0 To 2
                    If Not upData(i) Is Nothing Then
                        uint_crc = sectors(i)(0).nCrc
                        Select Case i
                            Case 0
                                Me.m_UsbCommHandler.GetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC, nCrcCheck)
                                If nCrcCheck <> uint_crc Then
                                    Me.m_UsbCommHandler.SetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC, uint_crc)
                                End If
                            Case 1
                                Me.m_UsbCommHandler.GetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_2, nCrcCheck)
                                If nCrcCheck <> uint_crc Then
                                    Me.m_UsbCommHandler.SetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_2, uint_crc)
                                End If
                            Case 2
                                Me.m_UsbCommHandler.GetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_3, nCrcCheck)
                                If nCrcCheck <> uint_crc Then
                                    Me.m_UsbCommHandler.SetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_3, uint_crc)
                                End If
                        End Select
                    End If
                Next
            End If

        ElseIf bStatus AndAlso m_Action And BikiAction.BK_MAPS Then
            ' Perform the Data Uploads
            If bStatus Then
                For i As Integer = 0 To 2
                    If bStatus And m_Action And (2 ^ i) AndAlso Not IsNothing(upData(i)) AndAlso upData(i).Length = SectorSize Then
                        If Not EraseSector(sectors, i, 0) Then ' Erase Sector
                            bReset = True
                            bStatus = False
                            OnErrMessage(upload_error.eUpErrErase, i)
                        ElseIf Not UploadSector(upData(i), i, 0) Then ' Upload Data
                            bStatus = False
                            OnErrMessage(upload_error.eUpErrUpload, i)
                            Select Case i
                                Case 0
                                    Me.m_UsbCommHandler.SetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC, 0)
                                Case 1
                                    Me.m_UsbCommHandler.SetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_2, 0)
                                Case 2
                                    Me.m_UsbCommHandler.SetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_3, 0)
                            End Select
                        Else
                            ' Write the CRC
                            uint_crc = sectors(i)(0).nCrc
                            Select Case i
                                Case 0
                                    Me.m_UsbCommHandler.SetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC, uint_crc)
                                Case 1
                                    Me.m_UsbCommHandler.SetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_2, uint_crc)
                                Case 2
                                    Me.m_UsbCommHandler.SetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_3, uint_crc)
                            End Select

                            OnErrMessage(upload_error.eUpErrUploadOK, i)
                        End If
                    End If
                Next
            End If
        End If

        ' Upload Saves Car Data
        If bStatus AndAlso Not IsNothing(upCarData) AndAlso upCarData.Length = SectorSize Then
            If Not EraseSector(sectors, 3, 0) Then ' Erase Sector
                bStatus = False
                OnMessage(String.Format("Failed to erase saved configuration"))
            ElseIf Not UploadSector(upCarData, 3, 0) Then ' Upload Data
                bStatus = False
                OnMessage(String.Format("Failed to upload saved configuration"))
            Else
                OnMessage(String.Format("Successfuly uploaded saved configuration"))
                OnErrMessage(upload_error.eUpErrUploadOK, 3)
            End If
        End If

        If bStatus And bReset Then
            Return thread_result.rslt_allok_reset_required
        ElseIf bStatus And Not bReset Then
            Return thread_result.rslt_allok
        Else
            Return thread_result.rslt_comms_error
        End If

    End Function

    ''' <summary>
    ''' Performs a Upload given the action and the data for a Bikirom Version 3 Hardware Board
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Overrides Function HwV3Process() As thread_result
        Dim upData(14)() As Byte
        Dim upCarData(1)() As Byte
        Dim bStatus As Boolean = True
        Dim data()() As Byte = m_carBase.Maps
        Dim Sectors As typFlashSector()() = Me.HwV3Sectors
        mProgressMax = 0

        ' Establish the maximum number of sectors that require erasing/uploading
        Dim sectorCount As Integer = 0
        For i As Integer = 0 To 7
            If m_Action And 2 ^ i AndAlso Not IsNothing(data(i)) AndAlso data(i).Length = SectorSize Then
                ReDim upData(i)(SectorSize - 1)

                ' Copy the array
                Array.Copy(m_carBase.getMap(i), 0, upData(i), 0, SectorSize)

                ' Inject CRC and security
                InjectSecurityCrc(upData(i))

                ' Calculate after injection
                CalculateCrc(upData(i), Sectors(i))

                mProgressMax += SectorSize * 2
            Else
                ' Exclude self if not correctly set up
                m_Action = m_Action And (&HFFFFFFFFUL Xor CUInt(2 ^ i))
            End If
        Next

        ' Prepare the car file for uploading!
        If m_Action And BikiAction.BK_CFG Then
            ' Serialize..
            Dim carData As Byte() = SerializeCarData(True)

            If Not IsNothing(carData) AndAlso carData.Length >= SectorSize Then
                ReDim upCarData(0)(SectorSize - 1)
                ReDim upCarData(1)(SectorSize - 1)

                Array.Copy(carData, 0, upCarData(0), 0, SectorSize)
                Array.Copy(carData, CLng(SectorSize), upCarData(1), 0, CLng(carData.Length - SectorSize))
            End If

            m_Action = m_Action Or BikiAction.BK_EEPROM

            '            mProgressMax += SectorSize * 2
        End If

        ' Upload EEPROM data
        If m_Action And BikiAction.BK_EEPROM Then
            mProgressMax += CarBase.EEPROM_SIZE

            Try
                bStatus = UploadEEPROM(m_carBase.getBikSettings.Data, 2)

                If bStatus Then Me.m_UsbCommHandler.ResetDevice()
            Catch
                bStatus = False
            End Try
        End If

        If bStatus Then
            Dim timeout As Integer = 40

            While timeout > 0 And Not Me.m_UsbCommHandler.Initialised
                Threading.Thread.Sleep(100)
                timeout -= 1
            End While

            If Not Me.m_UsbCommHandler.Initialised Then
                bStatus = False
            End If
        End If

        Dim failSector As Boolean = False

        Dim verifiedData() As Byte = Nothing
        Dim uploadData() As Byte = Nothing
        Dim nToSector As Byte

        If bStatus AndAlso m_Action And BikiAction.BK_MAPS AndAlso Me.m_UsbCommHandler.UsbInformation.OsVersion >= &H1D Then
            Debug.Print("Begining the Upload w/ Copy functions")

            'Flash Copy style
            For BankNo As Integer = 0 To 1
                Dim bReturn As thread_result = UploadFastVerified(Sectors, upData, BankNo)

                If bReturn <> thread_result.rslt_allok Then
                    Return bReturn
                End If
            Next

        ElseIf bStatus Then
        '------------------------------------------------------------------------------------------------------------------------
        ' Below code is previous before crazy copying!!!

        ' For bankNo As Byte = 0 To 1 ' for each bank
        For BankNo As Integer = 0 To 1
            For i As Integer = 0 To upData.Length - 1 ' for each map
                If Not IsNothing(upData(i)) AndAlso upData(i).Length = SectorSize Then
                    If downloadCrcs(Sectors(i), BankNo) Then
                        failSector = False
                        For s As Integer = 0 To UBound(Sectors(i))
                            If Sectors(i)(s).nBank1CRC <> Sectors(i)(s).nCrc Then
                                Sectors(i)(s).eAction = Sectors(i)(s).eAction Or _eAction.BANK1
                                Sectors(i)(0).eAction = Sectors(i)(0).eAction Or _eAction.TODO1
                                Sectors(i)(0).eAction = Sectors(i)(0).eAction Or _eAction.BANK1
                            End If
                        Next
                        If Sectors(i)(0).eAction And _eAction.TODO1 Then
                            ' Something to do. Upload all data then do CRC
                            Dim offset As Integer
                            For sec As Integer = 0 To UBound(Sectors(i))
                                If failSector Then Exit For
                                If sec = 0 Then
                                    offset = 16
                                Else
                                    offset = 0
                                End If
                                If Sectors(i)(sec).eAction And _eAction.BANK1 Then
                                    If Not EraseSubSector(Sectors, i, BankNo, sec, 4) Then
                                        OnErrMessage(upload_error.eUpErrErase, nToSector, BankNo)
                                        ' Erase Failed
                                        failSector = True
                                    ElseIf Not UploadSubSector(Sectors, upData(i), i, sec, BankNo, 4, offset) Then ' Always start from offset 16! leaves the CRC blank!
                                        OnErrMessage(upload_error.eUpErrUpload, nToSector, BankNo)
                                        ' Uploading Failed
                                        failSector = True
                                    Else
                                        OnErrMessage(upload_error.eUpErrUploadOK, nToSector, BankNo)
                                        ' Upload OK
                                    End If
                                End If
                            Next
                            If Not failSector Then
                                ' Upload crc's
                                If Not UploadCRCs(Sectors(i), BankNo, 4) Then
                                    ' Failed to upload sectors
                                    failSector = True
                                    OnErrMessage(upload_error.eUpErrCRC, nToSector, BankNo)
                                End If
                            Else
                                    '  OnErrMessage(upload_error.eUpErrUpload, nToSector, BankNo)
                                Return thread_result.rslt_board_fault
                            End If
                        End If
                    Else
                        Return thread_result.rslt_comms_error
                    End If
                End If
            Next
        Next
        End If

        If bStatus AndAlso m_Action And BikiAction.BK_CFG Then
            ' Perform the Bikirom File Upload
            For i As Integer = 0 To 1
                If Not IsNothing(upCarData(i)) AndAlso upCarData(i).Length = SectorSize Then
                    If Not EraseSector(Sectors, 15, i, 4) Then ' Erase Sector
                        OnMessage(String.Format("Erasing saved configuration part {0} of 2 failed", i + 1))
                    ElseIf Not UploadSector(upCarData(i), 15, i, 4) Then ' Upload Data
                        OnMessage(String.Format("Uploading saved configuration part {0} of 2 failed", i + 1))
                    Else
                        OnMessage(String.Format("Uploaded saved configutation part {0} of 2 successfuly", i + 1))
                    End If
                End If
            Next
        End If

        If bStatus Then
            Return thread_result.rslt_allok
        Else
            Return thread_result.rslt_comms_error
        End If

    End Function

    Private Function UploadFastVerified(ByVal Sectors()() As typFlashSector, ByVal UpData()() As Byte, ByVal BankNo As Byte) As thread_result
        Dim failSector As Boolean = False
        Dim bStatus As Boolean = False
        Dim verifiedData() As Byte = Nothing
        Dim uploadData() As Byte = Nothing
        Dim nFromSector As Byte
        Dim nToSector As Byte
        Dim nOffset As UInt32
        Dim nSectorOffset As UInt32
        Dim nLength As Int32
        Dim nSize As UInt32

        ' Clear out ToDo
        For n1 As Byte = 0 To UBound(Sectors)
            For n2 As Byte = 0 To UBound(Sectors(n1))
                Sectors(n1)(n2).eAction = _eAction.NONE
                Sectors(n1)(n2).nBank1CRC = 0
            Next
        Next

        ' Verify what needs doing
        For i As Integer = 0 To UpData.Length - 1 ' for each map
            If Not IsNothing(UpData(i)) AndAlso UpData(i).Length = SectorSize Then
                If Not downloadCrcs(Sectors(i), BankNo) Then
                    OnMessage("Downloading CRC's failed for bank " & BankNo)
                    Return thread_result.rslt_board_fault
                Else
                    failSector = False
                    For s As Integer = 0 To UBound(Sectors(i))
                        If Sectors(i)(s).nBank1CRC <> Sectors(i)(s).nCrc Then
                            failSector = True
                            Sectors(i)(s).eAction = Sectors(i)(s).eAction Or _eAction.TODO1
                            Sectors(i)(0).eAction = Sectors(i)(0).eAction Or _eAction.TODO1
                        Else
                            Sectors(i)(s).eAction = Sectors(i)(s).eAction Or _eAction.VERIFIED
                        End If
                    Next
                    If Not failSector Then
                        ' Sector is makred as OK!
                        OnMessage(String.Format("Map {0} bank {1} is already up to date", i, BankNo))
                        Debug.Print("Sector {0} Bank {1} is marked as complete", i, BankNo)
                        Sectors(i)(0).eAction = Sectors(i)(0).eAction Or _eAction.COMPLETE
                    Else
                        mProgressMax += SectorSize
                        OnMessage(String.Format("Map {0} bank {1} will be updated", i, BankNo))
                        Debug.Print("Secotr {0} Bank {1} is markes as incomplete", i, BankNo)
                    End If
                End If
            End If
        Next

        ' Look for what needs updating!
        For i As Integer = 0 To UpData.Length - 1 ' for each map
            If Not IsNothing(UpData(i)) AndAlso UpData(i).Length = SectorSize Then

                ' Check if this Map needs part/full updating!
                If Not Sectors(i)(0).eAction And _eAction.COMPLETE Then
                    ' Initialise verified data to nothing
                    verifiedData = Nothing
                    uploadData = UpData(i)
                    nToSector = i

                    For nVerifyLookup As Integer = 0 To UpData.Length - 1
                        If Sectors(nVerifyLookup)(0).eAction And _eAction.COMPLETE Then
                            verifiedData = UpData(nVerifyLookup)
                            nFromSector = nVerifyLookup
                            OnMessage("Found verified data, Performing fast upload on map " & nToSector)
                            Debug.Print("Found Verified Sector {0} Bank {1}", nFromSector, BankNo)
                            Exit For
                        End If
                    Next

                    failSector = False
                    If Not IsNothing(verifiedData) Then
                        ' Perform Special Upload here
                        '--------------------------------------------------------------------------------------------------------

                        nSectorOffset = 0
                        ' For each subsector
                        For nSubSector As Integer = 0 To Sectors(nToSector).Length - 1
                            nSize = Sectors(nToSector)(nSubSector).nSize

                            If Sectors(nToSector)(nSubSector).eAction And _eAction.TODO1 Then
                                If Not EraseSubSector(Sectors, nToSector, BankNo, nSubSector, 4) Then
                                    ' OnErrMessage(upload_error.eUpErrErase, nToSector, BankNo)
                                    ' Erase Failed
                                    Return thread_result.rslt_board_fault
                                Else
                                    ' Offset for initial CRCs
                                    If nSubSector = 0 Then
                                        nOffset = &H10
                                    Else
                                        nOffset = 0
                                    End If

                                    Do
                                        nLength = 0

                                        While (nLength + nOffset < nSize) AndAlso _
                                        (verifiedData(nOffset + nLength + nSectorOffset) = uploadData(nOffset + nLength + nSectorOffset) _
                                        And verifiedData(nOffset + 1 + nLength + nSectorOffset) = uploadData(nOffset + nLength + 1 + nSectorOffset))

                                            ' Skip the 0xFF's as erased flash is already known to be 0xFF
                                            If uploadData(nOffset + nLength + nSectorOffset) = &HFF _
                                            And uploadData(nOffset + nLength + nSectorOffset + 1) = &HFF _
                                            And nLength = 0 _
                                            Then
                                                nOffset += 2
                                            Else
                                                nLength += 2
                                            End If

                                        End While

                                        ' Do Copy
                                        If nLength AndAlso Not Me.CopySubSector(Sectors, nFromSector, nToSector, nSectorOffset + nOffset, nLength, BankNo, 1) Then
                                            OnErrMessage(upload_error.eUpErrCopy, nToSector, BankNo)
                                            Return thread_result.rslt_board_fault
                                        End If

                                        nOffset += nLength '+ nNudgeLength

                                        If (nOffset < nSize) Then
                                            '---------------------------------------------------
                                            ' Look backwards in 256 byte chunks to find the number of changed bytes
                                            nLength = System.Math.Min(256, nSize - nOffset)
                                            While nLength > 2 AndAlso _
                                              (verifiedData(nOffset + nLength + nSectorOffset - 2) = uploadData(nOffset + nLength + nSectorOffset - 2) _
                                            And verifiedData(nOffset - 1 + nLength + nSectorOffset) = uploadData(nOffset + nLength - 1 + nSectorOffset))
                                                nLength -= 2
                                            End While

                                            If nLength = 0 Then
                                                Throw New ArithmeticException("Major error in fast uploading procedure, BikiSoft coding error!")
                                            End If

                                            ' Do Upload of nLength Bytes
                                            If nLength > 0 AndAlso Not UploadSubSector(Sectors, uploadData, nToSector, nSubSector, BankNo, 4, nOffset, nLength) Then
                                                OnErrMessage(upload_error.eUpErrUpload, nToSector, BankNo)
                                                Return thread_result.rslt_board_fault
                                            Else

                                            End If

                                            nOffset += nLength

                                        End If

                                    Loop Until (nOffset >= nSize)

                                End If
                            Else
                                '    OnMessage(String.Format("Skipping map {0} bank {1}, data verified", nToSector, nSubSector))
                            End If
                            nSectorOffset += nSize
                        Next ' For Each SubSector

                        ' Upload the CRC for said Sector
                        If Not UploadCRCs(Sectors(nToSector), BankNo, 4) Then
                            ' Failed to upload sectors
                            '  OnErrMessage(upload_error.eUpErrCRC, nToSector, BankNo)
                            Return thread_result.rslt_board_fault
                        Else
                            OnErrMessage(upload_error.eUpErrUploadOK, nToSector, BankNo)
                            ' Mark that sector as complete!
                            Sectors(nToSector)(0).eAction = Sectors(nToSector)(0).eAction Or _eAction.COMPLETE
                        End If

                        '--------------------------------------------------------------------------------------------------------
                    Else
                        ' Perform Normal Upload here
                        '--------------------------------------------------------------------------------------------------------
                        For sec As Integer = 0 To UBound(Sectors(i))
                            If failSector Then Exit For
                            If sec = 0 Then
                                nOffset = 16
                            Else
                                nOffset = 0
                            End If
                            If Sectors(i)(sec).eAction And _eAction.TODO1 Then
                                If Not EraseSubSector(Sectors, i, BankNo, sec, 4) Then
                                    ' OnErrMessage(upload_error.eUpErrErase, nToSector, BankNo)
                                    ' Erase Failed
                                    failSector = True
                                ElseIf Not UploadSubSector(Sectors, UpData(i), i, sec, BankNo, 4, nOffset) Then ' Always start from offset 16! leaves the CRC blank!
                                    OnErrMessage(upload_error.eUpErrUpload, nToSector, BankNo)
                                    ' Uploading Failed
                                    failSector = True
                                End If
                            End If
                        Next
                        If Not failSector Then
                            ' Upload crc's
                            If Not UploadCRCs(Sectors(i), BankNo, 4) Then
                                ' Failed to upload sectors
                                failSector = True
                                OnErrMessage(upload_error.eUpErrUpload, nToSector, BankNo)
                            Else
                                OnErrMessage(upload_error.eUpErrUploadOK, nToSector, BankNo)
                                ' Upload OK
                                Sectors(nToSector)(0).eAction = Sectors(nToSector)(0).eAction Or _eAction.COMPLETE
                            End If
                        Else
                            'OnErrMessage(upload_error.eUpErrUpload, nToSector, BankNo)
                            Return thread_result.rslt_board_fault
                        End If
                    End If
                    '--------------------------------------------------------------------------------------------------------

                End If
            End If
        Next
    End Function

    Overrides Function HwV4Process() As thread_result
        Return thread_result.rslt_bikisoft_error
    End Function

    Private Sub InjectSecurityCrc(ByRef Data As Byte())
        Dim crc32 As New libCRC32
        Dim crc As UInt32
        ' Calculate the crc32!
        crc = crc32.GetByteArrayCrc32(Data)
        ' Insert the crc 32
        Array.Copy(System.BitConverter.GetBytes(crc), 0, Data, 0, 4)
        ' Place the special secret code
        'Array.Copy(cv_BytesFromHex("3040105A669123"), 0, Data, 3211, 7)
    End Sub

    ''' <summary>
    ''' Saves the car into the serialized format
    ''' </summary>
    ''' <param name="HwVer3"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function SerializeCarData(ByVal HwVer3 As Boolean) As Byte()
        Dim data() As Byte
        Dim DataStream As New MemoryStream()
        Dim serializer As New BinaryFormatter
        Dim f_TempCar As CarBase = ObjectCopy(m_carBase)
        f_TempCar.setForUpload()
        Dim f_memstream As New MemoryStream
        serializer.Serialize(f_memstream, f_TempCar)

        ' ---------------------------------------------- Zip and Encrypt
        Dim f_ZipStream As New MemoryStream
        CompressFile(f_memstream, f_ZipStream, True)
        Dim f_fullstream As New MemoryStream()

        If Not HwVer3 Then
            f_fullstream.SetLength(65528)
        Else
            f_fullstream.SetLength(131064)
        End If

        f_fullstream.Write(f_ZipStream.ToArray, 0, f_ZipStream.Length)

        For i As Integer = f_ZipStream.Length To f_fullstream.Length
            f_fullstream.WriteByte(0)
        Next

        Dim f_tmstream As New MemoryStream(f_fullstream.ToArray)
        Dim f_encStream As New MemoryStream()
        CryptFile("I5 i7 N07 B35T t() D0 \\'4|-|7 iS ASdlhpi324_+_0=09-8)&*(&^$&^)&%$^$@#hjkN;L:kjbdiy@gbb@bkdb@ lkB", f_tmstream, f_encStream, True)

        data = f_encStream.ToArray

        Return data
    End Function

    ''' <summary>
    ''' Erases a sector of flash on the bikirom board
    ''' </summary>
    ''' <param name="SectorAddrs"></param>
    ''' <param name="Sector"></param>
    ''' <param name="Bank"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function EraseSector(ByVal SectorAddrs As typFlashSector()(), ByVal Sector As Byte, ByVal Bank As Byte, Optional ByVal Retries As Byte = 0) As Boolean
        Dim f_Frame As Comm.Comm_Frame
        m_UsbCommHandler.Timeout = 8000

        For i As Integer = 0 To UBound(SectorAddrs(Sector))
            Try
                Debug.Print("Erase 0x{1} Beging : {0}", Now.Millisecond, Hex(SectorAddrs(Sector)(i).nAddress + (Bank * BankSize)))
                f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_RUN_COMMAND, SectorAddrs(Sector)(i).nAddress + (Bank * BankSize), Comm.Comm_Frame.BikiFrameAction.RUN_ERASESECTOR)
                Select Case m_UsbCommHandler.SendFrame(f_Frame, RetryNum:=3)
                    Case Comm.Comm_Frame.BikiFrameResponse.CMD_OK
                        Return True
                    Case Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_FAILED
                        OnErrMessage(upload_error.eUpErrFlashFault, Sector, Bank)
                        Return False
                    Case Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_TIMEOUT
                        OnErrMessage(upload_error.eUpErrFlashTimeout, Sector, Bank)
                        Return False
                    Case Else
                        OnErrMessage(upload_error.eUpErrErase, Sector, Bank)
                        Return False
                End Select
                Debug.Print("Erase Ending : {0}", Now.Millisecond)
            Catch ex As Comm_Exceptions
                If Retries > 0 Then
                    Return EraseSector(SectorAddrs, Sector, Bank, Retries - 1)
                Else
                    OnErrMessage(upload_error.eUpErrErase, Sector, Bank)
                    Return False
                End If
            End Try
        Next

        Return True

    End Function

    Private Function EraseSubSector(ByVal SectorAddrs As typFlashSector()(), ByVal Sector As Byte, ByVal bank As Byte, ByVal subSector As Byte, Optional ByVal Retries As Byte = 0) As Boolean
        Dim f_Frame As Comm.Comm_Frame
        m_UsbCommHandler.Timeout = 8000
        Try
            f_Frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_RUN_COMMAND, SectorAddrs(Sector)(subSector).nAddress + (bank * BankSize), Comm.Comm_Frame.BikiFrameAction.RUN_ERASESECTOR)
            Select Case m_UsbCommHandler.SendFrame(f_Frame, RetryNum:=3)
                Case Comm.Comm_Frame.BikiFrameResponse.CMD_OK
                    Return True
                Case Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_FAILED
                    OnErrMessage(upload_error.eUpErrFlashFault, Sector, bank)
                    Return False
                Case Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_TIMEOUT
                    OnErrMessage(upload_error.eUpErrFlashTimeout, Sector, bank)
                    Return False
                Case Else
                    OnErrMessage(upload_error.eUpErrErase, Sector, bank)
                    Return False
            End Select
        Catch ex As Comm_Exceptions
            If Retries > 0 Then
                Return EraseSubSector(SectorAddrs, Sector, bank, subSector, Retries - 1)
            Else
                OnErrMessage(upload_error.eUpErrErase, Sector, bank)
                Return False
            End If
        End Try

        Return True
    End Function

    ''' <summary>
    ''' Uploads a sector of data
    ''' </summary>
    ''' <param name="Data">raw Byte array to upload</param>
    ''' <param name="Sector">Sector to write it to</param>
    ''' <param name="Bank">Bank to write it to</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function UploadSector(ByVal Data As Byte(), ByVal Sector As Byte, ByVal Bank As Byte, Optional ByVal Retries As Byte = 0) As Boolean
        Dim packetSize As UInt16 = m_UsbCommHandler.MaxTxPacket - 10 - 6
        Dim packet(packetSize - 1) As Byte
        Dim frame As Comm.Comm_Frame
        Dim nRetries As Integer

        Try
            m_UsbCommHandler.Timeout = 200

            ' Upload in the biggest packets possible
            For i As Integer = 0 To (Data.Length - 1) Step packetSize
                nRetries = 5
                If i + packetSize > Data.Length Then
                    packetSize = Data.Length - i
                    ReDim packet(packetSize - 1)
                    Debug.Print("Packet goes over boundry, decreasing size")
                End If

                Debug.Print("Uploading Address : {0} Len: {1}", Hex((SectorSize * Sector) + (Bank * BankSize) + i), packetSize)

                Array.Copy(Data, i, packet, 0, packetSize)
                If Not BlankPacket(packet) Then
                    frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_FLASH_DATA _
                                                , (SectorSize * Sector) + (Bank * BankSize) + i _
                                                , Comm.Comm_Frame.BikiFrameAction.WRITE, packet)
                    If m_UsbCommHandler.SendFrame(frame, , , 10) <> Comm.Comm_Frame.BikiFrameResponse.CMD_OK Then
                        Return False
                    End If
                End If

                ' Report the progress back to the main thread
                IncrementProgress(packetSize)

                ' Perform cancel check
                If bgw.CancellationPending Then
                    eventArgs.Cancel = True
                    OnMessage("Uploading canceled")
                    Return False
                End If
            Next

            Return True
        Catch ex As Comm_Exceptions
            If ex.Response = Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_FAILED Or _
                ex.Response = Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_TIMEOUT Then
                Return False
            Else
                Return False 'UploadSector(Data, Sector, Bank, Retries - 1)
            End If
        End Try
    End Function

    ''' <summary>
    ''' Copies a Sub Sector or Part thereof between banks of memory. This will improve upload speeds imensly!
    ''' </summary>
    ''' <param name="FromSector">Copy from sector number</param>
    ''' <param name="ToSector">Copy to sector number</param>
    ''' <param name="Offset">Offset within sector</param>
    ''' <param name="Length">Length of copy within sector</param>
    ''' <param name="Bank">Memory bank specified</param>
    ''' <param name="Retries">Retry count</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function CopySubSector(ByVal Sectors As typFlashSector()(), ByVal FromSector As UInt32, ByVal ToSector As UInt32, ByVal Offset As UInt32, ByVal Length As UInt32, ByVal Bank As Byte, Optional ByVal Retries As Byte = 0) As Boolean
        Dim frame As Comm.Comm_Frame
        Dim nFrom, nTo, nLength As UInt32

        Try
            nFrom = (Bank * BankSize) + Offset + (FromSector * SectorSize)
            nTo = (Bank * BankSize) + Offset + (ToSector * SectorSize)
            nLength = Length

            Debug.Print("{0} to {1} Copied from {2}", Hex(nTo), Hex(nTo + nLength - 1), Hex(nFrom))

            frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_FLASH_COPY, nFrom, nTo, nLength)
            If m_UsbCommHandler.SendFrame(frame, , , 3) <> Comm.Comm_Frame.BikiFrameResponse.CMD_OK Then
                Return False
            End If

            IncrementProgress(nLength)

            Return True
        Catch ex As Comm_Exceptions
            If ex.Response <> Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_FAILED And _
                        ex.Response <> Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_TIMEOUT And _
                        Retries > 0 _
                        Then
                Return CopySubSector(Sectors, FromSector, ToSector, Offset, Length, Bank, Retries - 1)
            Else
                Return False
            End If
        End Try
    End Function

    ''' <summary>
    ''' Uploads a Sector and/or Sub Sector to flash. Also writes the appropriate CRC block at the completion of the write
    ''' </summary>
    ''' <param name="Sectors">Hardware Sector Definitions</param>
    ''' <param name="Data">byte array of data</param>
    ''' <param name="Sector">sector to upload</param>
    ''' <param name="SubSector">-1 for all sub sectors</param>
    ''' <param name="Bank">Bank number</param>
    ''' <param name="Retries">Number of retries before failure</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function UploadSubSector(ByVal Sectors As typFlashSector()(), ByVal Data As Byte(), ByVal Sector As Byte, ByVal SubSector As Integer, ByVal Bank As Byte, Optional ByVal Retries As Byte = 0, Optional ByVal Offset As UInt32 = 0, Optional ByVal Length As UInt32 = 0) As Boolean
        Dim packetSize As UInt16 = m_UsbCommHandler.MaxTxPacket - 10 - 6
        Dim packet(packetSize - 1) As Byte
        Dim frame As Comm.Comm_Frame
        Dim nAdrData As Long
        Dim nAdrHard As Long

        Try
            m_UsbCommHandler.Timeout = 1000

            If Length = 0 Then
                Length = Sectors(Sector)(SubSector).nSize - Offset
            End If

            ' Upload in the biggest packets possible
            For i As Integer = Offset To Offset + Length - 1 Step packetSize
                If i + packetSize > Sectors(Sector)(SubSector).nSize Then
                    packetSize = Sectors(Sector)(SubSector).nSize - i
                    ReDim packet(packetSize - 1)
                    Debug.Print("Packet goes over boundry, decreasing size")
                End If

                If i + packetSize > Offset + Length Then
                    packetSize = Offset + Length - i
                    ReDim packet(packetSize - 1)
                    Debug.Print("Packet goes over length, decreasing size")
                End If

                ' calculate the addresses
                nAdrData = Sectors(Sector)(SubSector).nAddress - Sectors(Sector)(0).nAddress + i
                nAdrHard = Sectors(Sector)(SubSector).nAddress + i + (Bank * BankSize)

                Array.Copy(Data, nAdrData, packet, 0, packetSize)

                If Not BlankPacket(packet) Then
                    Debug.Print("{0} to {1} Uploaded", Hex(nAdrHard), Hex(nAdrHard + packetSize - 1))
                    frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_FLASH_DATA _
                                                , nAdrHard _
                                                , Comm.Comm_Frame.BikiFrameAction.WRITE, packet)
                    If m_UsbCommHandler.SendFrame(frame, , , 4) <> Comm.Comm_Frame.BikiFrameResponse.CMD_OK Then
                        Return False
                    End If
                End If

                ' Report the progress back to the main thread
                IncrementProgress(packetSize)

                ' Perform cancel check
                If bgw.CancellationPending Then
                    eventArgs.Cancel = True
                    Return False
                End If

            Next

            Return True
        Catch ex As Comm_Exceptions
            If ex.Response <> Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_FAILED And _
            ex.Response <> Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_TIMEOUT And _
            Retries > 0 _
            Then
                Return UploadSubSector(Sectors, Data, Sector, SubSector, Bank, Retries - 1)
            Else
                Return False
            End If
        End Try
    End Function

    Private Function UploadEEPROM(ByVal data() As Byte, Optional ByVal Retries As UInt16 = 0) As Boolean
        Dim PacketSize As UInt16 = 124 - 10 - 6 ' m_CommHandle.UsbInformation.MaxTxPacket
        Dim packet(PacketSize - 1) As Byte
        Dim frame As Comm.Comm_Frame

        m_UsbCommHandler.Timeout = 2000
        Try
            For i As Integer = 0 To data.Length - 1 Step PacketSize
                If i + PacketSize > data.Length Then
                    PacketSize = data.Length - i
                    ReDim packet(PacketSize - 1)
                    Debug.Print("Packet goes over boundry, decreasing size")
                End If

                Array.Copy(data, i, packet, 0, PacketSize)

                If Not BlankPacket(packet) Then
                    Debug.Print("Uploading Address : {0} Len: {1}", Hex(i), PacketSize)
                    frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_EEPROM_DATA _
                                                , i _
                                                , Comm.Comm_Frame.BikiFrameAction.WRITE, packet)
                    If m_UsbCommHandler.SendFrame(frame, , False, 4) <> Comm.Comm_Frame.BikiFrameResponse.CMD_OK Then
                        Return False
                    End If
                End If

                ' Report the progress back to the main thread
                IncrementProgress(PacketSize)

                ' Perform cancel check
                If bgw.CancellationPending Then
                    eventArgs.Cancel = True
                    Return False
                End If

            Next

            Return True
        Catch ex As Comm_Exceptions
            If Retries > 0 Then
                Return UploadEEPROM(data, Retries - 1)
            Else
                Return False
            End If

        End Try

        Return True
    End Function

    Private Function UploadCRCs(ByVal Sectors As typFlashSector(), Optional ByVal Bank As Integer = 0, Optional ByVal retries As UInt16 = 0) As Boolean
        Dim packetsize As Byte = ((Sectors.Length * 4))
        Dim packet(packetsize - 1) As Byte
        Dim frame As Comm.Comm_Frame

        Try
            m_UsbCommHandler.Timeout = 300
            For i As Integer = 0 To Sectors.Length - 1
                Array.Copy(BitConverter.GetBytes(Sectors(i).nCrc), 0, packet, i * 4, 4)
            Next

            frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_FLASH_DATA _
                                                          , Sectors(0).nAddress + (Bank * BankSize) _
                                                          , Comm.Comm_Frame.BikiFrameAction.WRITE, packet)
            If m_UsbCommHandler.SendFrame(frame, , , 10) <> Comm.Comm_Frame.BikiFrameResponse.CMD_OK Then
                Return False
            Else
                Return True
            End If
        Catch ex As Comm_Exceptions
            If ex.Response <> Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_FAILED And _
            ex.Response <> Comm.Comm_Frame.BikiFrameResponse.FLASH_WRITE_TIMEOUT And _
            retries > 0 _
            Then
                Return UploadCRCs(Sectors, Bank, retries - 1)
            Else
                Return False
            End If
        End Try
    End Function



End Class
